import type { Response } from "@/core/models";
import { UserToken } from '@/consts'
import UniP from "./uni-promise";
import { getRequestHost } from './host';
import { handleLoginGetToken } from '@/core/utils';
import { useNetWorkHook } from '@/core/hooks';

type TReqOptions = Pick<UniApp.RequestOptions, 'method' | 'data' | 'header'>;
type TReqMethodOptions = Omit<TReqOptions, 'method'>;
type TResData = UniApp.RequestSuccessCallbackResult['data'];

let isRefreshing = true;
let subscribers = [];
const useNetWork = useNetWorkHook();

function onAccessTokenFetched() {
	subscribers.forEach((callback) => {
		callback();
	})
	subscribers = [];
	isRefreshing = true;
}

function addSubscriber(callback : Function) {
	subscribers.push(callback)
}

const request = async <T = TResData>(url : string, { method, data, header = {} } : TReqOptions, auth : boolean = true, callBack ?: Function) : Promise<Response<T>> => {

	// 检查是否存在网络
	const isConnected : boolean = await useNetWork.checkNetWorkOffline();
	if (!isConnected) {
		return Promise.reject({
			data: undefined,
			code: 500,
			msg: '网络跑小差啦~',
			status: false,
			otherData: '网络跑小差啦~'
		});
	}

	return new Promise(async (resolve, _) => {
		const res = await UniP.request<T>({
			url: url.indexOf('http') >= 0 ? url : `${getRequestHost()}/${url}`,
			method,
			data,
			header: {
				...header,
				'Authorization': `Bearer ${uni.getStorageSync(UserToken)}`
			}
		});

		if (callBack) {
			return callBack(res);
		}
		// 授权过期
		if (res.code === 14007) {
			addSubscriber(() => {
				request<T>(url, { method, data, header }, auth, resolve)
			});
			if (isRefreshing) {
				await handleLoginGetToken();
				onAccessTokenFetched();
				isRefreshing = true;
			}
			isRefreshing = false;
		} else {
			isRefreshing = true;
			return resolve(res);
		}
	});
}

const upload = async <T = TResData>(url : string, file : any) : Promise<Response<T>> => {
	// await useRequestInterceptor(url, header);
	// accessToken  需要处理accessToken 过期
	return UniP.uploadFile<T>({
		url: `${getRequestHost()}/${url}`,
		filePath: file,
		fileType: 'image',
		name: 'file',
		header: {
			'Accept': 'application/json',
			'Content-Type': 'multipart/form-data',
			'Authorization': `Bearer ${uni.getStorageSync(UserToken)}`
		},
		formData: {
			'method': 'images.upload',
			'upfile': file
		},
	})
}


const options = <T = TResData>(url : string, options : TReqMethodOptions = {}) : Promise<Response<T>> => {
	return request<T>(url, { ...options, method: 'OPTIONS' });
}

const get = <T = TResData>(url : string, options : TReqMethodOptions = {}, auth : boolean = true) : Promise<Response<T>> => {
	return request<T>(url, { ...options, method: 'GET' }, auth);
}

const head = <T = TResData>(url : string, options : TReqMethodOptions = {}) : Promise<Response<T>> => {
	return request<T>(url, { ...options, method: 'HEAD' });
}

const post = <T = TResData>(url : string, options : TReqMethodOptions = {}, auth : boolean = false) : Promise<Response<T>> => {
	return request<T>(url, { ...options, method: 'POST' }, auth);
}

const put = <T = TResData>(url : string, options : TReqMethodOptions = {}) : Promise<Response<T>> => {
	return request<T>(url, { ...options, method: 'PUT' });
}

const del = <T = TResData>(url : string, options : TReqMethodOptions = {}) : Promise<Response<T>> => {
	return request<T>(url, { ...options, method: 'DELETE' });
}

const trace = <T = TResData>(url : string, options : TReqMethodOptions = {}) : Promise<Response<T>> => {
	return request<T>(url, { ...options, method: 'TRACE' });
}

const connect = <T = TResData>(url : string, options : TReqMethodOptions = {}) : Promise<Response<T>> => {
	return request<T>(url, { ...options, method: 'CONNECT' });
}

const uploadFile = <T = TResData>(url : string, file : any) : Promise<Response<T>> => {
	return upload(url, file);
}
export { options, get, head, post, put, del, trace, connect, uploadFile }